<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>高阶函数</title>
</head>

<body>
    <p>高阶函数是指至少满足下列条件之一的函数</p>
    <p>函数可以作为参数被传递</p>

    <p>函数可以作为返回值输出</p>

    <script>
        // 函数作为参数被传递 回调函数
        // 1 在ajax异步请求应用中

        // 2 委托另一个函数来执行

        // 3 Array.prototype.sort 接收一个函数当做参数 这个函数封装了数组的排序规则

        // 从小排到大

        let n1 = [1, 3, 2].sort(function (a, b) {
            console.log('a', a, 'b', b)
            return a - b
        })
        console.log(n1)

        // 判断数据类型
        let isType = function (type) {
            return function (obj) {
                return Object.prototype.toString.call(obj) === "[object " + type + "]"
            }
        };
        let isString = isType('String')
        let isArray = isType('Array')
        // console.log(isString('11'))
        // console.log('isArray', isArray(['1']))

        // 使用循环语句来批量注册这些isType 函数
        var Type = {}
        for (let i = 0, type; type = ['Number', 'String', 'Array'][i++];) {
            (function (type) {
                Type['is' + type] = function (obj) {
                    return Object.prototype.toString.call(obj) === '[object ' + type + ']'
                }
            })(type)
        }
        console.log(Type.isArray([]), 'Type.isArray([])');

        // 单例模式 getSingle
        var getSingle = function (fn) {
            var ret;
            return function () {
                return ret || (ret = fn.apply(this, arguments))
            }
        }
        var getScript = getSingle(function () {
            return document.createElement('script')
        })
        var s1 = getScript()
        var s2 = getScript()
        // console.log(s1 === s2)


        // AOP 面向切面编程 JavaScript中实现aop 都是指把一个函数 "动态织入"到另外一个函数之中
        Function.prototype.before = function (beforefn) {
            var __self = this; // 保存原函数的引用
            return function () { // 保存包含了原函数和新函数的"代理" 函数
                beforefn.apply(this, arguments) // 执行新函数 修正this
                return __self.apply(this, arguments) // 执行原函数
            }
        }
        Function.prototype.after = function (afterfn) {
            var __self = this;
            return function () {
                var ret = __self.apply(this, arguments)
                afterfn.apply(this, arguments);
                return ret
            }
        }
        var func1 = function () {
            console.log(2)
        }
        func1 = func1.before(function () {
            // console.log(1)
        }).after(function () {
            // console.log('afet')
        }).before(function () {
            // console.log('bef')
        })
        func1()

        // 高阶函数其他应用

        // 1 柯里化 又称部分求值

        // 3 函数节流
        let throttle = function (fn, interval) {
            let __self = fn, // 保存需要被延迟执行的函数引用
                timer, // 定时器
                firstTime = true; // 是否是第一次调用
            return function () {
                let args = arguments,
                    __me = this;
                if (firstTime) { // 如果是第一次调用 立刻执行
                    __self.apply(__me, args);
                    return firstTime = false;
                }
                if (timer) return false;
                timer = setInterval(function () {
                    clearTimeout(timer);
                    timer = null;
                    __self.apply(__me, args)
                }, interval || 300)
            }
        };

        var a = 1;
        // window.onresize = throttle(function () {
        //     console.log('onresize', a++);
        // }, 300);

        // 4 分时函数  在短时间内创建大量dom 这样会让浏览器吃不消

        var ary = []
        for (let i = 0; i < 1000; i++) {
            ary.push(i)
        }
        // 
        var renderFriendList = function(data) {
            let start = Date.now()
            console.log(start, 'start');
            for( var i = 0, l = data.length; i < l; i++) {
                var div = document.createElement('div');
                div.innerHTML = i;
                document.body.appendChild(div)
            }
            let end = Date.now()    // 大概 4 - 9ms
            console.log(end - start, '所花时间');
        }
        renderFriendList(ary);
        
        // 限制一次性创建过多节点
        /**
        *  ary 所需数据
        *  fn  创建节点的逻辑
        *  count 每次创建的数量
        */

        var timeChunk = function( ary, fn, count) {
            var obj, t;
            var len = ary.length;
            var start = function() {    // 开始创建
                // 获取每次要创建的个数
                for (let i = 0; i < Math.min( count || 1, ary.length); i ++) {
                    var obj = ary.shift(); // 截取第一个
                    fn(obj) // 作为参数
                }
            }
            return function() {
                t = setInterval( function() {
                    if (ary.length === 0 ) {
                        return clearInterval(t)
                    }
                    start()
                }, 200)
            }
        }
    
        var renderFriendList1 = timeChunk(ary, function(n) {
            var div = document.createElement('div');
            div.innerHTML = n + '$1';
            document.body.appendChild(div);
        }, 8)
        renderFriendList1()

        // 5 惰性加载函数
        





    </script>

</body>

</html>